home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / net_ser.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  21KB  |  952 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // net_ser.c
  21.  
  22. #include "quakedef.h"
  23. #include "net_ser.h"
  24. #include "dosisms.h"
  25. #include "crc.h"
  26.  
  27. #include "net_comx.c"
  28.  
  29. // serial protocol
  30.  
  31. #define SERIAL_PROTOCOL_VERSION 3
  32.  
  33. // The serial protocol is message oriented.  The high level message format is
  34. // a one byte message type (MTYPE_xxx), data, and a 16-bit checksum.  All
  35. // multi-byte fields are sent in network byte order.  There are currently 4
  36. // MTYPEs defined.  Their formats are as follows:
  37. //
  38. // MTYPE_RELIABLE     sequence      data_length   data       checksum   eom
  39. // MTYPE_UNRELIABLE   sequence      data_length   data       checksum   eom
  40. // MTYPE_ACK          sequence      checksum      eom
  41. // MTYPE_CONTROL      data_length   data          checksum   eom
  42. //
  43. // sequence is an 8-bit unsigned value starting from 0
  44. // data_length is a 16-bit unsigned value; it is the length of the data only
  45. // the checksum is a 16-bit value.  the CRC formula used is defined in crc.h.
  46. //              the checksum covers the entire messages, excluding itself
  47. // eom is a special 2 byte sequence used to mark the End Of Message.  This is
  48. //              needed for error recovery.
  49. //
  50. // A lot of behavior is based on knowledge of the upper level Quake network
  51. // layer.  For example, only one reliable message can be outstanding (pending
  52. // reception of an MTYPE_ACK) at a time.
  53. //
  54. // The low level routines used to communicate with the modem are not part of
  55. // this protocol.
  56. //
  57. // The CONTROL messages are only used for session establishment.  They are
  58. // not reliable or sequenced.
  59.  
  60. #define MTYPE_RELIABLE            0x01
  61. #define MTYPE_UNRELIABLE        0x02
  62. #define MTYPE_CONTROL            0x03
  63. #define MTYPE_ACK                0x04
  64. #define MTYPE_CLIENT            0x80
  65.  
  66. #define ESCAPE_COMMAND            0xe0
  67. #define ESCAPE_EOM                0x19
  68.  
  69. static qboolean listening = false;
  70.  
  71.  
  72. typedef struct SerialLine_s
  73. {
  74.     struct SerialLine_s    *next;
  75.     qsocket_t            *sock;
  76.     int                    lengthStated;
  77.     int                    lengthFound;
  78.     int                    tty;
  79.     qboolean            connected;
  80.     qboolean            connecting;
  81.     qboolean            client;
  82.     double                connect_time;
  83.     unsigned short        crcStated;
  84.     unsigned short        crcValue;
  85.     byte                currState;
  86.     byte                prevState;
  87.     byte                mtype;
  88.     byte                sequence;
  89. } SerialLine;
  90.  
  91. #define STATE_READY        0
  92. #define STATE_SEQUENCE    1
  93. #define STATE_LENGTH1    2
  94. #define STATE_LENGTH2    3
  95. #define STATE_DATA        4
  96. #define STATE_CRC1        5
  97. #define STATE_CRC2        6
  98. #define STATE_EOM        7
  99. #define STATE_ESCAPE    8
  100. #define STATE_ABORT        9
  101.  
  102. SerialLine serialLine[NUM_COM_PORTS];
  103.  
  104. int myDriverLevel;
  105.  
  106. static void Serial_SendACK (SerialLine *p, byte sequence);
  107.  
  108.  
  109. static void ResetSerialLineProtocol (SerialLine *p)
  110. {
  111.     p->connected = false;
  112.     p->connecting = false;
  113.     p->currState = STATE_READY;
  114.     p->prevState = STATE_READY;
  115.     p->lengthFound = 0;
  116. }
  117.  
  118.  
  119. static int ProcessInQueue(SerialLine *p)
  120. {
  121.     int    b;
  122.  
  123.     while (1)
  124.     {
  125.         b = TTY_ReadByte(p->tty);
  126.         if (b == ERR_TTY_NODATA)
  127.             break;
  128.  
  129.         if (b == ERR_TTY_LINE_STATUS)
  130.         {
  131.             p->currState = STATE_ABORT;
  132.             continue;
  133.         }
  134.         if (b == ERR_TTY_MODEM_STATUS)
  135.         {
  136.             p->currState = STATE_ABORT;
  137.             return -1;
  138.         }
  139.  
  140.         if (b == ESCAPE_COMMAND)
  141.             if (p->currState != STATE_ESCAPE)
  142.             {
  143.                 p->prevState = p->currState;
  144.                 p->currState = STATE_ESCAPE;
  145.                 continue;
  146.             }
  147.  
  148.         if (p->currState == STATE_ESCAPE)
  149.         {
  150.             if (b == ESCAPE_EOM)
  151.             {
  152.                 if (p->prevState == STATE_ABORT)
  153.                 {
  154.                     p->currState = STATE_READY;
  155.                     p->lengthFound = 0;
  156.                     continue;
  157.                 }
  158.  
  159.                 if (p->prevState != STATE_EOM)
  160.                 {
  161.                     p->currState = STATE_READY;
  162.                     p->lengthFound = 0;
  163.                     Con_DPrintf("Serial: premature EOM\n");
  164.                     continue;
  165.                 }
  166.  
  167.                 switch (p->mtype)
  168.                 {
  169.                     case MTYPE_RELIABLE:
  170.                         Con_DPrintf("Serial: sending ack %u\n", p->sequence);
  171.                         Serial_SendACK (p, p->sequence);
  172.                         if (p->sequence == p->sock->receiveSequence)
  173.                         {
  174.                             p->sock->receiveSequence = (p->sequence + 1) & 0xff;
  175.                             p->sock->receiveMessageLength += p->lengthFound;
  176.                         }
  177.                         else
  178.                             Con_DPrintf("Serial: reliable out of order; got %u wanted %u\n", p->sequence, p->sock->receiveSequence);
  179.                         break;
  180.  
  181.                     case MTYPE_UNRELIABLE:
  182.                         p->sock->unreliableReceiveSequence = (p->sequence + 1) & 0xff;
  183.                         p->sock->receiveMessageLength += p->lengthFound;
  184.                         break;
  185.  
  186.                     case MTYPE_ACK:
  187.                         Con_DPrintf("Serial: got ack %u\n", p->sequence);
  188.                         if (p->sequence == p->sock->sendSequence)
  189.                         {
  190.                             p->sock->sendSequence = (p->sock->sendSequence + 1) & 0xff;
  191.                             p->sock->canSend = true;
  192.                         }
  193.                         else
  194.                             Con_DPrintf("Serial: ack out of order; got %u wanted %u\n",p->sequence, p->sock->sendSequence);
  195.                         break;
  196.  
  197.                     case MTYPE_CONTROL:
  198.                         p->sock->receiveMessageLength += p->lengthFound;
  199.                         break;
  200.                     }
  201.  
  202.                 p->currState = STATE_READY;
  203.                 p->lengthFound = 0;
  204.                 continue;
  205.             }
  206.  
  207.  
  208.             if (b != ESCAPE_COMMAND)
  209.             {
  210.                 p->currState = STATE_ABORT;
  211.                 Con_DPrintf("Serial: Bad escape sequence\n");
  212.                 continue;
  213.             }
  214.  
  215.             // b == ESCAPE_COMMAND
  216.             p->currState = p->prevState;
  217.         }
  218.  
  219.         p->prevState = p->currState;
  220.  
  221. //DEBUG
  222.         if (p->sock->receiveMessageLength + p->lengthFound > NET_MAXMESSAGE)
  223.         {
  224.             Con_DPrintf("Serial blew out receive buffer: %u\n", p->sock->receiveMessageLength + p->lengthFound);
  225.             p->currState = STATE_ABORT;
  226.         }
  227.         if (p->sock->receiveMessageLength + p->lengthFound == NET_MAXMESSAGE)
  228.         {
  229.             Con_DPrintf("Serial hit receive buffer limit: %u\n", p->sock->receiveMessageLength + p->lengthFound);
  230.             p->currState = STATE_ABORT;
  231.         }
  232. //end DEBUG
  233.  
  234.         switch (p->currState)
  235.         {
  236.             case STATE_READY:
  237.                 CRC_Init(&p->crcValue);
  238.                 CRC_ProcessByte(&p->crcValue, b);
  239.                 if (p->client)
  240.                 {
  241.                     if ((b & MTYPE_CLIENT) != 0)
  242.                     {
  243.                         p->currState = STATE_ABORT;
  244.                         Con_DPrintf("Serial: client got own message\n");
  245.                         break;
  246.                     }
  247.                 }
  248.                 else
  249.                 {
  250.                     if ((b & MTYPE_CLIENT) == 0)
  251.                     {
  252.                         p->currState = STATE_ABORT;
  253.                         Con_DPrintf("Serial: server got own message\n");
  254.                         break;
  255.                     }
  256.                     b &= 0x7f;
  257.                 }
  258.                 p->mtype = b;
  259.                 if (b != MTYPE_CONTROL)
  260.                     p->currState = STATE_SEQUENCE;
  261.                 else
  262.                     p->currState = STATE_LENGTH1;
  263.                 if (p->mtype < MTYPE_ACK)
  264.                 {
  265.                     p->sock->receiveMessage[p->sock->receiveMessageLength] = b;
  266.                     p->lengthFound++;
  267.                 }
  268.                 break;
  269.  
  270.             case STATE_SEQUENCE:
  271.                 p->sequence = b;
  272.                 CRC_ProcessByte(&p->crcValue, b);
  273.                 if (p->mtype != MTYPE_ACK)
  274.                     p->currState = STATE_LENGTH1;
  275.                 else
  276.                     p->currState = STATE_CRC1;
  277.                 break;
  278.  
  279.             case STATE_LENGTH1:
  280.                 p->lengthStated = b * 256;
  281.                 CRC_ProcessByte(&p->crcValue, b);
  282.                 p->currState = STATE_LENGTH2;
  283.                 break;
  284.  
  285.             case STATE_LENGTH2:
  286.                 p->lengthStated += b;
  287.                 CRC_ProcessByte(&p->crcValue, b);
  288.                 if (p->mtype == MTYPE_RELIABLE && p->lengthStated > MAX_MSGLEN)
  289.                 {
  290.                     p->currState = STATE_ABORT;
  291.                     Con_DPrintf("Serial: bad reliable message length %u\n", p->lengthStated);
  292.                 }
  293.                 else if (p->mtype == MTYPE_UNRELIABLE && p->lengthStated > MAX_DATAGRAM)
  294.                 {
  295.                     p->currState = STATE_ABORT;
  296.                     Con_DPrintf("Serial: bad unreliable message length %u\n", p->lengthStated);
  297.                 }
  298.                 else
  299.                 {
  300.                     p->currState = STATE_DATA;
  301.                     if (p->mtype < MTYPE_ACK)
  302.                     {
  303.                         *(short *)&p->sock->receiveMessage [p->sock->receiveMessageLength + 1] = p->lengthStated;
  304.                         p->lengthFound += 2;
  305.                     }
  306.                 }
  307.                 break;
  308.  
  309.             case STATE_DATA:
  310.                 p->sock->receiveMessage[p->sock->receiveMessageLength + p->lengthFound] = b;
  311.                 p->lengthFound++;
  312.                 CRC_ProcessByte(&p->crcValue, b);
  313.                 if (p->lengthFound == p->lengthStated + 3)
  314.                     p->currState = STATE_CRC1;
  315.                 break;
  316.  
  317.             case STATE_CRC1:
  318.                 p->crcStated = b * 256;
  319.                 p->currState = STATE_CRC2;
  320.                 break;
  321.  
  322.             case STATE_CRC2:
  323.                 p->crcStated += b;
  324.                 if (p->crcStated == CRC_Value(p->crcValue))
  325.                 {
  326.                     p->currState = STATE_EOM;
  327.                 }
  328.                 else
  329.                 {
  330.                     p->currState = STATE_ABORT;
  331.                     Con_DPrintf("Serial: Bad crc\n");
  332.                 }
  333.                 break;
  334.  
  335.             case STATE_EOM:
  336.                 p->currState = STATE_ABORT;
  337.                 Con_DPrintf("Serial: Bad message format\n");
  338.                 break;
  339.  
  340.             case STATE_ABORT:
  341.                 break;
  342.         }
  343.     }
  344.     return 0;
  345. }
  346.  
  347.  
  348. int Serial_Init (void)
  349. {
  350.     int     n;
  351.  
  352. // LATER do Win32 serial support
  353. #ifdef    _WIN32
  354.     return -1;
  355. #endif
  356.  
  357.     if (COM_CheckParm("-nolan"))
  358.         return -1;
  359.     if (COM_CheckParm ("-noserial"))
  360.         return -1;
  361.  
  362.     myDriverLevel = net_driverlevel;
  363.  
  364.     if (TTY_Init())
  365.         return -1;
  366.  
  367.     for (n = 0; n < NUM_COM_PORTS; n++)
  368.     {
  369.         serialLine[n].tty = TTY_Open(n);
  370.         ResetSerialLineProtocol (&serialLine[n]);
  371.     }
  372.  
  373.     Con_Printf("Serial driver initialized\n");
  374.     serialAvailable = true;
  375.  
  376.     return 0;
  377. }
  378.  
  379.  
  380. void Serial_Shutdown (void)
  381. {
  382.     int     n;
  383.  
  384.     for (n = 0; n < NUM_COM_PORTS; n++)
  385.     {
  386.         if (serialLine[n].connected)
  387.             Serial_Close(serialLine[n].sock);
  388.     }
  389.  
  390.     TTY_Shutdown();
  391. }
  392.  
  393.  
  394. void Serial_Listen (qboolean state)
  395. {
  396.     listening = state;
  397. }
  398.  
  399.  
  400. qboolean Serial_CanSendMessage (qsocket_t *sock)
  401. {
  402.     return sock->canSend;
  403. }
  404.  
  405.  
  406. qboolean Serial_CanSendUnreliableMessage (qsocket_t *sock)
  407. {
  408.     return TTY_OutputQueueIsEmpty(((SerialLine *)sock->driverdata)->tty);
  409. }
  410.  
  411.  
  412. int Serial_SendMessage (qsocket_t *sock, sizebuf_t *message)
  413. {
  414.     SerialLine *p;
  415.     int n;
  416.     unsigned short crc;
  417.     byte b;
  418.  
  419.     p = (SerialLine *)sock->driverdata;
  420.     CRC_Init (&crc);
  421.  
  422.     // message type
  423.     b = MTYPE_RELIABLE;
  424.     if (p->client)
  425.         b |= MTYPE_CLIENT;
  426.     TTY_WriteByte(p->tty, b);
  427.     CRC_ProcessByte (&crc, b);
  428.  
  429.     // sequence
  430.     b = p->sock->sendSequence;
  431.     TTY_WriteByte(p->tty, b);
  432.     if (b == ESCAPE_COMMAND)
  433.         TTY_WriteByte(p->tty, b);
  434.     CRC_ProcessByte (&crc, b);
  435.  
  436.     // data length
  437.     b = message->cursize >> 8;
  438.     TTY_WriteByte(p->tty, b);
  439.     if (b == ESCAPE_COMMAND)
  440.         TTY_WriteByte(p->tty, b);
  441.     CRC_ProcessByte (&crc, b);
  442.     b = message->cursize & 0xff;
  443.     TTY_WriteByte(p->tty, b);
  444.     if (b == ESCAPE_COMMAND)
  445.         TTY_WriteByte(p->tty, b);
  446.     CRC_ProcessByte (&crc, b);
  447.  
  448.     // data
  449.     for (n = 0; n < message->cursize; n++)
  450.     {
  451.         b = message->data[n];
  452.         TTY_WriteByte(p->tty, b);
  453.         if (b == ESCAPE_COMMAND)
  454.             TTY_WriteByte(p->tty, b);
  455.         CRC_ProcessByte (&crc, b);
  456.     }
  457.  
  458.     // checksum
  459.     b = CRC_Value (crc) >> 8;
  460.     TTY_WriteByte(p->tty, b);
  461.     if (b == ESCAPE_COMMAND)
  462.         TTY_WriteByte(p->tty, b);
  463.     b = CRC_Value (crc) & 0xff;
  464.     TTY_WriteByte(p->tty, b);
  465.     if (b == ESCAPE_COMMAND)
  466.         TTY_WriteByte(p->tty, b);
  467.  
  468.     // end of message
  469.     TTY_WriteByte(p->tty, ESCAPE_COMMAND);
  470.     TTY_WriteByte(p->tty, ESCAPE_EOM);
  471.  
  472.     TTY_Flush(p->tty);
  473.  
  474.     // mark sock as busy and save the message for possible retransmit
  475.     sock->canSend = false;
  476.     Q_memcpy(sock->sendMessage, message->data, message->cursize);
  477.     sock->sendMessageLength = message->cursize;
  478.     sock->lastSendTime = net_time;
  479.  
  480.     return 1;
  481. }
  482.  
  483.  
  484. static void ReSendMessage (qsocket_t *sock)
  485. {
  486.     sizebuf_t       temp;
  487.  
  488.     Con_DPrintf("Serial: re-sending reliable\n");
  489.     temp.data = sock->sendMessage;
  490.     temp.maxsize = sock->sendMessageLength;
  491.     temp.cursize = sock->sendMessageLength;
  492.     Serial_SendMessage (sock, &temp);
  493. }
  494.  
  495.  
  496. int Serial_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *message)
  497. {
  498.     SerialLine *p;
  499.     int n;
  500.     unsigned short crc;
  501.     byte b;
  502.  
  503.     p = (SerialLine *)sock->driverdata;
  504.  
  505.     if (!TTY_OutputQueueIsEmpty(p->tty))
  506.     {
  507.         TTY_Flush(p->tty);
  508.         return 1;
  509.     }
  510.  
  511.     CRC_Init (&crc);
  512.  
  513.     // message type
  514.     b = MTYPE_UNRELIABLE;
  515.     if (p->client)
  516.         b |= MTYPE_CLIENT;
  517.     TTY_WriteByte(p->tty, b);
  518.     CRC_ProcessByte (&crc, b);
  519.  
  520.     // sequence
  521.     b = p->sock->unreliableSendSequence;
  522.     p->sock->unreliableSendSequence = (b + 1) & 0xff;
  523.     TTY_WriteByte(p->tty, b);
  524.     if (b == ESCAPE_COMMAND)
  525.         TTY_WriteByte(p->tty, b);
  526.     CRC_ProcessByte (&crc, b);
  527.  
  528.     // data length
  529.     b = message->cursize >> 8;
  530.     TTY_WriteByte(p->tty, b);
  531.     if (b == ESCAPE_COMMAND)
  532.         TTY_WriteByte(p->tty, b);
  533.     CRC_ProcessByte (&crc, b);
  534.     b = message->cursize & 0xff;
  535.     TTY_WriteByte(p->tty, b);
  536.     if (b == ESCAPE_COMMAND)
  537.         TTY_WriteByte(p->tty, b);
  538.     CRC_ProcessByte (&crc, b);
  539.  
  540.     // data
  541.     for (n = 0; n < message->cursize; n++)
  542.     {
  543.         b = message->data[n];
  544.         TTY_WriteByte(p->tty, b);
  545.         if (b == ESCAPE_COMMAND)
  546.             TTY_WriteByte(p->tty, b);
  547.         CRC_ProcessByte (&crc, b);
  548.     }
  549.  
  550.     // checksum
  551.     b = CRC_Value (crc) >> 8;
  552.     TTY_WriteByte(p->tty, b);
  553.     if (b == ESCAPE_COMMAND)
  554.         TTY_WriteByte(p->tty, b);
  555.     b = CRC_Value (crc) & 0xff;
  556.     TTY_WriteByte(p->tty, b);
  557.     if (b == ESCAPE_COMMAND)
  558.         TTY_WriteByte(p->tty, b);
  559.  
  560.     // end of message
  561.     TTY_WriteByte(p->tty, ESCAPE_COMMAND);
  562.     TTY_WriteByte(p->tty, ESCAPE_EOM);
  563.  
  564.     TTY_Flush(p->tty);
  565.  
  566.     return 1;
  567. }
  568.  
  569.  
  570. static void Serial_SendACK (SerialLine *p, byte sequence)
  571. {
  572.     unsigned short crc;
  573.     byte b;
  574.  
  575.     CRC_Init (&crc);
  576.  
  577.     // message type
  578.     b = MTYPE_ACK;
  579.     if (p->client)
  580.         b |= MTYPE_CLIENT;
  581.     TTY_WriteByte(p->tty, b);
  582.     CRC_ProcessByte (&crc, b);
  583.  
  584.     // sequence
  585.     b = sequence;
  586.     TTY_WriteByte(p->tty, b);
  587.     if (b == ESCAPE_COMMAND)
  588.         TTY_WriteByte(p->tty, b);
  589.     CRC_ProcessByte (&crc, b);
  590.  
  591.     // checksum
  592.     b = CRC_Value (crc) >> 8;
  593.     TTY_WriteByte(p->tty, b);
  594.     if (b == ESCAPE_COMMAND)
  595.         TTY_WriteByte(p->tty, b);
  596.     b = CRC_Value (crc) & 0xff;
  597.     TTY_WriteByte(p->tty, b);
  598.     if (b == ESCAPE_COMMAND)
  599.         TTY_WriteByte(p->tty, b);
  600.  
  601.     // end of message
  602.     TTY_WriteByte(p->tty, ESCAPE_COMMAND);
  603.     TTY_WriteByte(p->tty, ESCAPE_EOM);
  604.  
  605.     TTY_Flush(p->tty);
  606. }
  607.  
  608.  
  609. static void Serial_SendControlMessage (SerialLine *p, sizebuf_t *message)
  610. {
  611.     unsigned short crc;
  612.     int n;
  613.     byte b;
  614.  
  615.     CRC_Init (&crc);
  616.  
  617.     // message type
  618.     b = MTYPE_CONTROL;
  619.     if (p->client)
  620.         b |= MTYPE_CLIENT;
  621.     TTY_WriteByte(p->tty, b);
  622.     CRC_ProcessByte (&crc, b);
  623.  
  624.     // data length
  625.     b = message->cursize >> 8;
  626.     TTY_WriteByte(p->tty, b);
  627.     if (b == ESCAPE_COMMAND)
  628.         TTY_WriteByte(p->tty, b);
  629.     CRC_ProcessByte (&crc, b);
  630.     b = message->cursize & 0xff;
  631.     TTY_WriteByte(p->tty, b);
  632.     if (b == ESCAPE_COMMAND)
  633.         TTY_WriteByte(p->tty, b);
  634.     CRC_ProcessByte (&crc, b);
  635.  
  636.     // data
  637.     for (n = 0; n < message->cursize; n++)
  638.     {
  639.         b = message->data[n];
  640.         TTY_WriteByte(p->tty, b);
  641.         if (b == ESCAPE_COMMAND)
  642.             TTY_WriteByte(p->tty, b);
  643.         CRC_ProcessByte (&crc, b);
  644.     }
  645.  
  646.     // checksum
  647.     b = CRC_Value (crc) >> 8;
  648.     TTY_WriteByte(p->tty, b);
  649.     if (b == ESCAPE_COMMAND)
  650.         TTY_WriteByte(p->tty, b);
  651.     b = CRC_Value (crc) & 0xff;
  652.     TTY_WriteByte(p->tty, b);
  653.     if (b == ESCAPE_COMMAND)
  654.         TTY_WriteByte(p->tty, b);
  655.  
  656.     // end of message
  657.     TTY_WriteByte(p->tty, ESCAPE_COMMAND);
  658.     TTY_WriteByte(p->tty, ESCAPE_EOM);
  659.  
  660.     TTY_Flush(p->tty);
  661. }
  662.  
  663.  
  664. static int _Serial_GetMessage (SerialLine *p)
  665. {
  666.     byte    ret;
  667.     short    length;
  668.  
  669.     if (ProcessInQueue(p))
  670.         return -1;
  671.  
  672.     if (p->sock->receiveMessageLength == 0)
  673.         return 0;
  674.  
  675.     ret = p->sock->receiveMessage[0];
  676.     length = *(short *)&p->sock->receiveMessage[1];
  677.     if (ret == MTYPE_CONTROL)
  678.         ret = 1;
  679.  
  680.     SZ_Clear (&net_message);
  681.     SZ_Write (&net_message, &p->sock->receiveMessage[3], length);
  682.  
  683.     length += 3;
  684.     p->sock->receiveMessageLength -= length;
  685.  
  686.     if (p->sock->receiveMessageLength + p->lengthFound)
  687.         Q_memcpy(p->sock->receiveMessage, &p->sock->receiveMessage[length], p->sock->receiveMessageLength + p->lengthFound);
  688.  
  689.     return ret;
  690. }
  691.  
  692. int Serial_GetMessage (qsocket_t *sock)
  693. {
  694.     SerialLine *p;
  695.     int        ret;
  696.  
  697.     p = (SerialLine *)sock->driverdata;
  698.  
  699.     ret = _Serial_GetMessage (p);
  700.  
  701.     if (ret == 1)
  702.         messagesReceived++;
  703.  
  704.     if (!sock->canSend)
  705.         if ((net_time - sock->lastSendTime) > 1.0)
  706.         {
  707.             ReSendMessage (sock);
  708.             sock->lastSendTime = net_time;
  709.         }
  710.  
  711.     return ret;
  712. }
  713.  
  714.  
  715. void Serial_Close (qsocket_t *sock)
  716. {
  717.     SerialLine *p = (SerialLine *)sock->driverdata;
  718.     TTY_Close(p->tty);
  719.     ResetSerialLineProtocol (p);
  720. }
  721.  
  722.  
  723. char *com_types[] = {"direct", "modem"};
  724. unsigned com_bauds[] = {9600, 14400, 19200, 28800, 57600};
  725.  
  726. void Serial_SearchForHosts (qboolean xmit)
  727. {
  728.     int        n;
  729.     SerialLine *p;
  730.  
  731.     if (sv.active)
  732.         return;
  733.  
  734.     if (hostCacheCount == HOSTCACHESIZE)
  735.         return;
  736.  
  737.     // see if we've already answered
  738.     for (n = 0; n < hostCacheCount; n++)
  739.         if (Q_strcmp (hostcache[n].cname, "#") == 0)
  740.             return;
  741.  
  742.     for (n = 0; n < NUM_COM_PORTS; n++)
  743.         if (TTY_IsEnabled(n))
  744.             break;
  745.     if (n == NUM_COM_PORTS)
  746.         return;
  747.     p = &serialLine[n];
  748.  
  749.     if (TTY_IsModem(p->tty))
  750.         return;
  751.  
  752.     sprintf(hostcache[hostCacheCount].name, "COM%u", n+1);
  753.     Q_strcpy(hostcache[hostCacheCount].map, "");
  754.     hostcache[hostCacheCount].users = 0;
  755.     hostcache[hostCacheCount].maxusers = 0;
  756.     hostcache[hostCacheCount].driver = net_driverlevel;
  757.     Q_strcpy(hostcache[hostCacheCount].cname, "#");
  758.     hostCacheCount++;
  759.  
  760.     return;
  761. }
  762.  
  763.  
  764. static qsocket_t *_Serial_Connect (char *host, SerialLine *p)
  765. {
  766.     int        ret;
  767.     double    start_time;
  768.     double    last_time;
  769.  
  770.     p->client = true;
  771.     if (TTY_Connect(p->tty, host))
  772.         return NULL;
  773.  
  774.     p->sock = NET_NewQSocket ();
  775.     p->sock->driver = myDriverLevel;
  776.     if (p->sock == NULL)
  777.     {
  778.         Con_Printf("No sockets available\n");
  779.         return NULL;
  780.     }
  781.     p->sock->driverdata = p;
  782.  
  783.     // send the connection request
  784.     start_time = SetNetTime();
  785.     last_time = 0.0;
  786.  
  787.     SZ_Clear(&net_message);
  788.     MSG_WriteByte(&net_message, CCREQ_CONNECT);
  789.     MSG_WriteString(&net_message, "QUAKE");
  790.     do
  791.     {
  792.         SetNetTime();
  793.         if ((net_time - last_time) >= 1.0)
  794.         {
  795.             Serial_SendControlMessage (p, &net_message);
  796.             last_time = net_time;
  797.             Con_Printf("trying...\n"); SCR_UpdateScreen ();
  798.         }
  799.         ret = _Serial_GetMessage (p);
  800.     }
  801.     while (ret == 0 && (net_time - start_time) < 5.0);
  802.  
  803.     if (ret == 0)
  804.     {
  805.         Con_Printf("Unable to connect, no response\n");
  806.         goto ErrorReturn;
  807.     }
  808.  
  809.     if (ret == -1)
  810.     {
  811.         Con_Printf("Connection request error\n");
  812.         goto ErrorReturn;
  813.     }
  814.  
  815.     MSG_BeginReading ();
  816.     ret = MSG_ReadByte();
  817.     if (ret == CCREP_REJECT)
  818.     {
  819.         Con_Printf(MSG_ReadString());
  820.         goto ErrorReturn;
  821.     }
  822.     if (ret != CCREP_ACCEPT)
  823.     {
  824.         Con_Printf("Unknown connection response\n");
  825.         goto ErrorReturn;
  826.     }
  827.  
  828.     p->connected = true;
  829.     p->sock->lastMessageTime = net_time;
  830.  
  831.     Con_Printf ("Connection accepted\n");
  832.  
  833.     return p->sock;
  834.  
  835. ErrorReturn:
  836.     TTY_Disconnect(p->tty);
  837.     return NULL;
  838. }
  839.  
  840. qsocket_t *Serial_Connect (char *host)
  841. {
  842.     int            n;
  843.     qsocket_t    *ret = NULL;
  844.  
  845.     // see if this looks like a phone number
  846.     if (*host == '#')
  847.         host++;
  848.     for (n = 0; n < Q_strlen(host); n++)
  849.         if (host[n] == '.' || host[n] == ':')
  850.             return NULL;
  851.  
  852.     for (n = 0; n < NUM_COM_PORTS; n++)
  853.         if (TTY_IsEnabled(n) && !serialLine[n].connected)
  854.             if ((ret = _Serial_Connect (host, &serialLine[n])))
  855.                 break;
  856.     return ret;
  857. }
  858.  
  859.  
  860. static qsocket_t *_Serial_CheckNewConnections (SerialLine *p)
  861. {
  862.     int    command;
  863.  
  864.     p->client = false;
  865.     if (!TTY_CheckForConnection(p->tty))
  866.         return NULL;
  867.  
  868.     if (TTY_IsModem(p->tty))
  869.     {
  870.         if (!p->connecting)
  871.         {
  872.             p->connecting = true;
  873.             p->connect_time = net_time;
  874.         }
  875.         else if ((net_time - p->connect_time) > 15.0)
  876.         {
  877.             p->connecting = false;
  878.             TTY_Disconnect(p->tty);
  879.             return NULL;
  880.         }
  881.     }
  882.  
  883.     p->sock = NET_NewQSocket ();
  884.     p->sock->driver = myDriverLevel;
  885.     if (p->sock == NULL)
  886.     {
  887.         Con_Printf("No sockets available\n");
  888.         return NULL;
  889.     }
  890.     p->sock->driverdata = p;
  891.  
  892.     SZ_Clear(&net_message);
  893.     if (_Serial_GetMessage(p) != 1)
  894.     {
  895.         NET_FreeQSocket(p->sock);
  896.         return NULL;
  897.     }
  898.  
  899.     MSG_BeginReading ();
  900.     command = MSG_ReadByte();
  901.  
  902.     if (command == CCREQ_SERVER_INFO)
  903.     {
  904.         if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
  905.             return NULL;
  906.  
  907.         if (MSG_ReadByte() != SERIAL_PROTOCOL_VERSION)
  908.             return NULL;
  909.  
  910.         SZ_Clear(&net_message);
  911.         MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
  912.         MSG_WriteString(&net_message, hostname.string);
  913.         MSG_WriteString(&net_message, sv.name);
  914.         MSG_WriteByte(&net_message, net_activeconnections);
  915.         MSG_WriteByte(&net_message, svs.maxclients);
  916.         Serial_SendControlMessage (p, &net_message);
  917.         SZ_Clear(&net_message);
  918.         return NULL;
  919.     }
  920.  
  921.     if (command != CCREQ_CONNECT)
  922.         return NULL;
  923.  
  924.     if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
  925.         return NULL;
  926.  
  927.     // send him back the info about the server connection he has been allocated
  928.     SZ_Clear(&net_message);
  929.     MSG_WriteByte(&net_message, CCREP_ACCEPT);
  930.     Serial_SendControlMessage (p, &net_message);
  931.     SZ_Clear(&net_message);
  932.  
  933.     p->connected = true;
  934.     p->connecting = false;
  935.     p->sock->lastMessageTime = net_time;
  936.     sprintf(p->sock->address, "COM%u", (int)((p - serialLine) + 1));
  937.  
  938.     return p->sock;
  939. }
  940.  
  941. qsocket_t *Serial_CheckNewConnections (void)
  942. {
  943.     int            n;
  944.     qsocket_t    *ret = NULL;
  945.  
  946.     for (n = 0; n < NUM_COM_PORTS; n++)
  947.         if (TTY_IsEnabled(n) && !serialLine[n].connected)
  948.             if ((ret = _Serial_CheckNewConnections (&serialLine[n])))
  949.                 break;
  950.     return ret;
  951. }
  952.